
/* GCSx
** PROGRESS.CPP
**
** Non-interactive progress meter popup window
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#include "all.h"

ProgressMeter::ProgressMeter(long long myTotal) : Window() { start_func
    // Keep it simple- total must be > 0
    if (myTotal < 1) myTotal = 1;
    total = myTotal;
    position = 0;
    myFrame = NULL;
    resize(screenWidth / 2, PROGRESS_METER_HEIGHT);
    openTimer = SDL_GetTicks();
    progressDone = 0;
    lastUpdate = SDL_GetTicks();
}

ProgressMeter::~ProgressMeter() { start_func
}

int ProgressMeter::tempFocus() const { start_func 
    return 1;
}

void ProgressMeter::openMeter() { start_func
    // Prevent duplication
    if (myFrame) {
        desktop->bringToTop(myFrame);
        return;
    }

    // We remember the frame pointer even though it'll delete itself
    myFrame = new FrameWindow(blankString, FrameWindow::RESIZING_OFF, FrameWindow::FRAMETYPE_BEVEL_BK, this, FrameWindow::TITLEBAR_OFF);
    
    // Center
    int xPos = (screenWidth - myFrame->getWidth()) / 2;
    if (xPos < 0) xPos = 0;
    int yPos = (screenHeight - myFrame->getHeight()) / 2;
    if (yPos < 0) yPos = 0;
    myFrame->show(xPos, yPos, FrameWindow::SHOW_CURRENT, FrameWindow::SHOW_CURRENT);
    updateDisplay();
}

void ProgressMeter::updateDisplay() { start_func
    setDirty(1);
    Uint32 ticks = SDL_GetTicks();
    if (ticks > lastUpdate) {
        lastUpdate = ticks + 3;
        SDL_PumpEvents();
        desktop->updateScreen();
    }
}
    
void ProgressMeter::updateProgress(long long myPosition) { start_func
    if (myPosition < 0) myPosition = 0;
    if (myPosition > total) myPosition = total;
    position = myPosition;

    if (myFrame == NULL) {
        Uint32 ticks = SDL_GetTicks();
        // (catch wraparound)
        if (ticks < openTimer) openTimer = SDL_GetTicks();
        else if (ticks - openTimer > DELAY_AUTO_OPEN) {
            openMeter();
        }
    }
    else {
        updateDisplay();
    }
}

void ProgressMeter::doneProgress(int cleanEvents) { start_func
    if (myFrame) {
        // Shouldn't clear focus/etc events... just SDL events like clicks/keys
        if (cleanEvents) desktop->initEventCleanup();
        closeTimer = SDL_GetTicks();
        progressDone = 1;
    }
    else delete this;
}

int ProgressMeter::event(int hasFocus, const SDL_Event* event) { start_func
    assert(event);
    
    switch (event->type) {
        case SDL_SPECIAL:
            if ((event->user.code & SDL_IDLE) && (progressDone)) {
                Uint32 ticks = SDL_GetTicks();
                // (catch wraparound)
                if (ticks < closeTimer) closeTimer = SDL_GetTicks();
                else if (ticks - closeTimer > DELAY_AUTO_CLOSE) {
                    myFrame->closeWindow();
                }
                return 1;
            }
            break;
    }
    return 0;
}

void ProgressMeter::display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) { start_func
    assert(destSurface);

    if (visible) {
        // If drawing, redraw all
        if ((dirty) || (toDisplay.w)) {
            getRect(toDisplay);
            toDisplay.x += xOffset;
            toDisplay.y += yOffset;

            dirty = totalDirty = 0;
            // Don't clip- for gradient purposes
            // intersectRects(toDisplay, clipArea);
        }
        
        xOffset += x;
        yOffset += y;
        
        // Anything to draw?
        if (toDisplay.w) {
            // Outermost
            SDL_SetClipRect(destSurface, &clipArea);
            SDL_FillRect(destSurface, &toDisplay, guiPacked[COLOR_BKFILL]);
            
            // Fill
            int w = (long long)(width - PROGRESS_METER_BORDER * 2) * position / total;
            if (w) drawGradient(xOffset + PROGRESS_METER_BORDER, yOffset + PROGRESS_METER_BORDER,
                                w, height - PROGRESS_METER_BORDER * 2,
                                guiRGB[COLOR_SELECTION1], guiRGB[COLOR_SELECTION2],
                                destSurface);
                                
            // Text
            int percent = position * (long long)100 / total;
            string text = intToStr(percent);
            text += "%";
            int size = fontWidth(text, FONT_STANDARD);
            drawText(text, guiRGB[COLOR_TEXTBOX], xOffset + (width - size) / 2,
                     yOffset + (height - fontHeight(FONT_STANDARD)) / 2, destSurface, FONT_STANDARD);
        }
    }
}

Window::WindowType ProgressMeter::windowType() const { start_func
    return WINDOW_CLIENT;
}

Window::WindowSort ProgressMeter::windowSort() const { start_func
    return WINDOWSORT_POPUP;
}

int ProgressMeter::wantsToBeDeleted() const { start_func
    return 1;
}
